package org.ace.logic.teamroom.impl;

import java.io.IOException;
import java.util.List;

import javax.annotation.Resource;
import  static org.ace.logic.teamroom.protocol.TeamProtocol.*;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;

import org.ace.biz.user.ITeamBiz;
import org.ace.endingCode.Amf3CodeUtils;
import org.ace.endingCode.SocketModel;
import org.ace.logic.IHandlerServ;
import org.ace.logic.teamroom.dto.InviteDTO;
import org.ace.logic.teamroom.dto.TeamDTO;
import org.ace.logic.user.AbstractUserHandlerImpl;
import org.ace.logic.user.dto.PlayerDTO;
import org.ace.model.TalkDTO;
import org.ace.model.TeamModel;
import org.ace.tool.impl.ErrorUtil;
import org.codehaus.groovy.runtime.ConvertedClosure;

import com.caucho.hessian.io.IOExceptionWrapper;

public class TeamHandlerServImpl extends AbstractUserHandlerImpl implements
		IHandlerServ {
	@Resource(name="teamBiz")
	private ITeamBiz teamBiz;
	
	@Override
	public void Colse(Channel channel) {
		leave(channel);

	}

	@Override
	protected void process(Channel channel, SocketModel message) {
		switch(message.getCommand())
		{
		 case CREATE_CREQ:
			 create(channel);
			 break;
		 case INVITE_CREQ:
			 invite(channel ,message);
			 break;
		 case JOIN_CREQ:
			 join(channel ,message);
			 break;
		 case LEAVE_CREQ :
			 leave(channel);
			 break;
		 case SYNC_TEAM_INFO_CREQ:
			 sync(channel);
			 break;
		 case DISMISS_CREQ:
			 dimiss(channel);
			 break;
		 case KICK_CREQ:
			 kick(channel,message);
			 break;
		 case TALK_CREQ:
			 talk(channel,message);
			 break;
			
		}

	}

	private void talk(Channel channel, SocketModel<String> message) {
		Integer userId=getUserId(channel);
		teamBrocastByUser(userId,TALK_BRO,message.getMessage());
		
	}
	private void teamBrocastByUser(Integer userId, int command, Object message) {
		//没有队伍 了 ，不可发送队伍聊天
		if(!teamBiz.hasTeam(userId)) return ;
		teamBrocast(teamBiz.getTeamId(userId),command,message);		
	}
	private void teamBrocast(Integer teamId, int command, Object message) {
		//temaId 获取 team 里面的playerId 群发队员
		TeamModel team = teamBiz.get(teamId);
		if(team==null)	return;
		SocketModel sm= createSocketModel(53363,message);
		
		try
		{
			/*先序列化 ，在发送避免了发送时 一次次的重复 序列化，优化的手段*/
			ByteBuf bf =Amf3CodeUtils.encode(sm);
			for(Integer playerId : team.getPlayers())
			{
				write(playerId,bf);
			}
		}
		catch(IOException e)
		{
			logger.info(ErrorUtil.decode(e));
		}
		
	}

	private void kick(Channel channel, SocketModel<Integer> message) {
		Integer userId = getUserId(channel);
		//服务器发送过来的消息是 要剔除的 id
		Integer targetId=message.getMessage();
		Integer result=teamBiz.kick(userId, targetId);
		
		if(result!=null)
		{//给队伍成员发送消息
			teamBrocast(result, KICK_BRO, targetId);
			//给被踢成员法师宏消息
			write(targetId, KICK_BRO, targetId);
		}
	}

	private void dimiss(Channel channel) {
		Integer userId = getUserId(channel);
		/*获取解散的队伍的列表*/
		List<Integer> result = teamBiz.dismiss(userId);
		if(result!=null)//已解散
		{
			for(Integer i : result)
			{//要发送的对象id 以此获取绑定的channel， commoned  消息体
				write(i,DISMISS_BRO,null);//已解散 只是接受消息方 不用消息体
			}
		}
		
	}

	private void sync(Channel channel) {
		Integer userId= getUserId(channel);
		if(!teamBiz.hasTeam(userId))
		{//角色没有队伍 不更变信息 ，因为消息定义来回接受 ，不回这个消息也没关系
			write(channel ,TEAM_INFO_CHANGE_BRO,null);
			return;
		}
		TeamModel team=teamBiz.get(teamBiz.getTeamId(userId));
		//发送队伍信息 改变 的消息体
		write(channel,TEAM_INFO_CHANGE_BRO,convert(team));
		
	}
	/*将TeamModel 数据模型转换为 传输模型*/
	private TeamDTO convert(TeamModel team) {
		TeamDTO dto=new TeamDTO();
		dto.leader=team.getLeaderId();
		PlayerDTO[] players=new PlayerDTO[team.getPlayers().size()];
		int i=0;
		//对每个模块的设计是都有考量的 team 只用于存 userId就行 玩家数据模型还是在 Player里
		for(int id : team.getPlayers())
		{
			players[i]=new PlayerDTO(playerBiz.get(id));
			i++;
		}
		dto.players=players;
		return dto;
	}

	private void leave(Channel channel) {
		Integer userId= getUserId(channel);
		if(!teamBiz.hasTeam(userId))
		{//这里其实是说 如果客户端 不在主队模式中 发了 离开请求 ，做一个数据正确性的判断
			//也是属于消息的 安全性检查
			return;
		}
		
		TeamModel team=teamBiz.get(teamBiz.getTeamId(userId));
		//移除队伍 和 teamBiz 层中的角色组队信息
		team.getPlayers().remove(userId);
		teamBiz.userTeamRemove(userId);
		//群发队员离开 的角色id，要离开的已在队伍中剔除 不会群发给自己
		teamBrocast(team.getId(),LEAVE_BRO, userId);
		//单独给自己返回 离开请求的 答复 已离开
		write(channel,LEAVE_BRO,userId);
		
		if(team.getLeaderId().equals(userId))
		{/*如果是队长离开了 ，当队伍人数还有的话 将剩余的第一个设置为*/
			if(team.getPlayers().size()>0)
			{
				team.setLeaderId(team.getPlayers().get(0));
				//群发消息变更
				teamBrocast(team.getId(), TEAM_INFO_CHANGE_BRO, convert(team));
			}
			else
			{
				//队伍已空 重复利用队伍
				teamBiz.addLast(team);
			}
		}
	}

	private void invite(Channel channel, SocketModel<Integer> message) {
		Integer userId=getUserId(channel);
		//获取被邀请者id
		Integer targetId = message.getMessage();
		
		//自身没有队伍 无法邀请他人	
		if(!teamBiz.hasTeam(userId))
		{  
			write(channel,INVITE_SRES,null); //返回消息 无法邀请 
			return; 
		}
		
		//一般来说 ,发出一个邀请，如果有权限 其他人也可以邀请的， 待续拓展
		TeamModel team = teamBiz.getByUserId(userId);
		if(!team.getLeaderId().equals(userId))//不是队长 不能邀请他人
		{
			write(channel,INVITE_SRES,null);
			return;
		}
		
		//返回空的消息体 则发起邀请者失败
		if(teamBiz.hasTeam(targetId))
		{
			write(channel, INVITE_SRES, null);
			return;
		}
		
		//
		InviteDTO dto = new InviteDTO();
		dto.teamId =team.getId();
		dto.userName = playerBiz.get(userId).getUsername();
		//通过被邀请者，发送teamId 和 邀请者 名字，谁邀请 加入 队伍
		write(targetId,INVITE_SRES,dto);
	}
	

	private void join(Channel channel, SocketModel<Integer> message) {
		Integer userId=getUserId(channel);
		Integer teamId=message.getMessage();
		TeamModel team=teamBiz.join(userId, teamId);
		
		if(team!= null)
		{
			//队伍群发，刷新队伍信息
			teamBrocast(teamId, TEAM_INFO_CHANGE_BRO, convert(team));
		}
		
	}

	private void create(Channel channel) {
		Integer userId=getUserId(channel);
		//已在队伍中 不能在创建队伍
		if(teamBiz.hasTeam(userId))
		{
			//有队伍 的话 将这个队伍信息返回给客户端
			write(channel, TEAM_INFO_CHANGE_BRO, convert(teamBiz.getByUserId(userId)));
		}
		//通知玩家创建成功
		write(channel,CREATE_SRES,convert(teamBiz.create(userId)));
	}

}
